<!--
 * @Author: wellington wellington@kreditme.id
 * @Date: 2023-11-09 10:48:30
 * @LastEditors: wellington wellington@kreditme.id
 * @LastEditTime: 2023-11-16 15:38:34
 * @FilePath: /background-removal/src/views/jsDemo.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
    <div style="text-align: left;">
        <div class="markdown">
            <div class="markdown-body" v-html="addhtml" ></div>
        </div>
    </div>
</template>

<script setup>
import "github-markdown-css/github-markdown-dark.css"
import hljs from 'highlight.js'
import 'highlight.js/styles/dark.css'
import {marked} from 'marked';
const render = new marked.Renderer()
marked.setOptions({
    renderer: render,
    highlight: (code, lang) => {
       
       if (lang && hljs.getLanguage(lang)) {
           return hljs.highlight(code, {language: lang}).value
       }
       return hljs.highlight(code).value
   }
})
const addhtml = marked.parse(`
### 1. 不使用循环和库，递归实现数组累加
\`\`\`js
const list = [1,3,5,7]

// 实现一个函数 表示 从数组i选项到末尾之和：
// add(0) ==> 1 + 3 + 5 + 7
// add(1) ==> 3 + 5 + 7
// 可以得出规律 add(0) = list[0] + add(0 + 1)

function add(i) {
    // 超过数组长度，就是0
    return i >= list.length ? 0 : list[i] + add(i + 1)
}
add(0)
\`\`\`
### 2. 不使用第三个变量，交换a和b的值
\`\`\`js
var a = 5  var b = 3
方式一：解构   [b, a] = [a,b]

方式二：混合的两种方式. 因为加法，所以只能针对数字
1. 相加 
a = a + b   b = a - b    a = a - b
1. 异或 原理：相同取0，不同取1
a = a ^ b     b = a ^  b    a = a ^  b

0101   5      
0011   3
------- 得到
0110  a
0011
------- 得到
0101  b
0110
------- 得到
0011
拓展：异或思路用在其他地方的示例：一个数组中只有一个数字出现一次，其他都出现了2次。找出这个数字： 
因为重复出现的数字异或以后直接为0了
function uniqueNumber(list) {
    return list.reduce((a,b) => a ^ b, 0)
}
\`\`\`
### 3. 通过逻辑与判断一个数字是不是2的整数倍, x > 1
\`\`\`js
function isPowerOf2(x) {
    return (x & (x - 1)) === 0
}
原理：2的整数倍的二进制有个特性: 只有第一位是1 ===> 2 (10) 4 (100) 8 (1000)
这个数字键去1 ，第一位一定是0. 比如：8 - 1 = 7 (0111)
再与该数字取与：都是1则为1，不同则为0. 得到的一定是0
1000  8
0111  7
--------
0000
\`\`\`
### 4. 说说对象的key，以及js最大安全整数

\`\`\`js
js的数字是以64位双精度浮点数形式存储，组成部分是 1 (正负符号) + 11 (指数) + 52 (尾数)
科学计数法示例-108： -1.08 * (10 ** 2)

最大安全正整数的标识：1.1111...111(尾数存52个1)， 规定尾数前面一定是1，那总共就是53个1。转为十进制刚好是：(2 ** 53) - 1
Number.MAX_SAFE_INTEGER  === (2 ** 53) - 1

32位单精度浮点数：组成部分是 1 (正负符号) + 8 (指数) + 23 (尾数)

32位最大无符号整数：就是符号和指数全部用来作为数字，32位都是1，转成十进制就是(2 ** 32) - 1 === 4294967295
我们知道32位最大无符号整数通常被当作一个对象的key是否作为升序的分界线。当key小于4294967295 就自动升序
示例：
const obj = {4294967299: 123, 4294967295: 234}  ===>  输出也是一样的
const obj1 = {4294967291: 123, 4294967290: 234}  ===>  输出{4294967290: 234, 4294967291: 123}

所以有一些题目：当循环obj2的时候，我们要知道依次输出的key是排序过的
const obj2 = {
    3: 'a',
    2: 'b',
    'name': 'jone'
}   ===> 输出2，3，’name‘

另外提一点：对象的key只能是字符串和symbol。当遇到这样的题目应该知道会有隐式转换
const a = {}
const b = {key: 12};
const c = {key: 345};
a[b] = 123
a[c] = 456
问：console.log(a[b]) 输出什么？
答案： 输出456。 因为不同的对象都被转为了字符串'[object object]'。
同理，数字也会转成字符串  ===>  const list = []  list[1] = 3 list['1'] = 8 更改的key是一样的

再看下面此题： 会打印多少次？ 
const start = 2 ** 53
const end = start + 100
for (let k = start; k < end; k++) {console.log('')}
结论是：因为数字太大了，无法预测，会出现奇怪的现象，差点给我电脑整奔溃，
如果要保证循环可控，判断一下，跳出循环
for (let k = start; k < end; k++) {
  if (!Number.isSafeInteger(k)) {
    console.log('Unsafe Integer Detected:', k);
    break;
  }
  console.log('');
}

现象：Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2  ===> 输出true

\`\`\`
### 5. 手写call函数
\`\`\`js
Function.prototype.myCall = function(thisArg, ...args){
    console.log(this)
    // 如果thisArg传进来的是非对象，转成对象
    const context = (thisArg === null || thisArg === undefined) ? globalThis : Object(thisArg)
   
    // 使用不会与第一参数属性重复的临时变量，将函数的this存储到第一参数中，然后执行
    const fn = Symbol()
    // 1.使用属性描述符赋值this，在node环境的add函数中打印this，不会有增加的Symbol属性fn。 // realthis { name: 1, [Symbol()]: [Function: add] }
    // 但是浏览器里还有，所以没啥意义
    // Object.defineProperty(context, fn, {
    //     enumerable: false,
    //     value: this
    // })
    // 2. 直接给fn赋值this
    context[fn] = this
    const result = context[fn](...args)

    // 删除临时变量
    delete context.fn
    return result

}
function add(a, b) {
    console.log('realthis', this)
    return this.name + a + b
}
add.myCall({name: 1}, 2, 3)
\`\`\`
6. 使用IntersectionObserver实现滚动到底部加载数据 / 图片懒加载
\`\`\`js
let observer = new IntersectionObserver(function(){
    entries.forEach((entry) => {
    if (entry.isIntersecting) {
    进入视口给图片src赋值，展示图片
    entry.target.src = entry.target.dataset.src // 这个dataset.src 是放在标签上的图片 <img class="img" v-for="img in images" :data-src="img"/>
    observer.unobserve(entry.target) // 停止监听这些元素
    }
  });
}, { 
    root: document.querySelector('#相对的元素'),  // 不写root默认浏览器视口
    threshold: 0.1   // 当出现在相对元素范围内10%的时候开始执行第一参数函数
});

const boxElList = document.querySelectorAll(".img"); // 
boxElList.forEach((el) => {
    observer.observe(el); // 监听所有图片
});

// 离开页面销毁observer,关闭观察器
observer.disconnect()
\`\`\`
`)

</script>

<style  scoped>
.markdown {
    background-color: #999;
    padding: 0 20%;
}
.markdown-body {
    background: inherit;
    line-height: 2;
    /* padding: 0 20%; */
}
</style>